From ff96fa159b84b7a46f10f551bc041316ea55735a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Jul 2015 11:49:19 -0700 Subject: [PATCH] Pass --cap-lints=allow instead of -Awarnings This commit adds support to Cargo to pass `--cap-lints allow` to all upstream dependencies instead of `-A warings`. This should serve the same purpose of suppressing warnings in upstream dependencies as well as preventing widespread breakage whenever a change to a lint is introduced in the compiler. --- src/cargo/ops/cargo_compile.rs | 10 ++-- src/cargo/ops/cargo_rustc/context.rs | 8 ++- src/cargo/ops/cargo_rustc/custom_build.rs | 4 +- src/cargo/ops/cargo_rustc/fingerprint.rs | 4 +- src/cargo/ops/cargo_rustc/mod.rs | 37 +++--------- src/cargo/ops/mod.rs | 2 +- src/cargo/util/config.rs | 20 ++----- src/cargo/util/mod.rs | 20 ++++--- src/cargo/util/rustc.rs | 50 ++++++++++++++++ tests/test_cargo_compile_git_deps.rs | 70 +++++++++++++++++++++++ tests/tests.rs | 15 +++-- 11 files changed, 170 insertions(+), 70 deletions(-) create mode 100644 src/cargo/util/rustc.rs diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index a92720804..9502d9444 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -126,7 +126,6 @@ pub fn compile_pkg<'a>(package: &Package, let override_ids = try!(source_ids_from_config(config, package.root())); let (packages, resolve_with_overrides, sources) = { - let rustc_host = config.rustc_host().to_string(); let mut registry = PackageRegistry::new(config); if let Some(source) = source { registry.preload(package.package_id().source_id(), source); @@ -146,13 +145,14 @@ pub fn compile_pkg<'a>(package: &Package, try!(registry.add_overrides(override_ids)); - let platform = target.as_ref().map(|e| &e[..]).or(Some(&rustc_host[..])); + let platform = target.as_ref().unwrap_or(&config.rustc_info().host); - let method = Method::Required{ + let method = Method::Required { dev_deps: true, // TODO: remove this option? features: &features, uses_default_features: !no_default_features, - target_platform: platform}; + target_platform: Some(&platform[..]), + }; let resolved_with_overrides = try!(ops::resolve_with_previous(&mut registry, package, method, @@ -397,7 +397,7 @@ fn scrape_build_config(config: &Config, requested_target: target.clone(), ..Default::default() }; - base.host = try!(scrape_target_config(config, config.rustc_host())); + base.host = try!(scrape_target_config(config, &config.rustc_info().host)); base.target = match target.as_ref() { Some(triple) => try!(scrape_target_config(config, &triple)), None => base.host.clone(), diff --git a/src/cargo/ops/cargo_rustc/context.rs b/src/cargo/ops/cargo_rustc/context.rs index 2782213dd..93eecb742 100644 --- a/src/cargo/ops/cargo_rustc/context.rs +++ b/src/cargo/ops/cargo_rustc/context.rs @@ -70,7 +70,9 @@ impl<'a, 'cfg> Context<'a, 'cfg> { } else { try!(Context::filename_parts(None, config)) }; - let target_triple = target.unwrap_or(config.rustc_host()).to_string(); + let target_triple = target.unwrap_or_else(|| { + &config.rustc_info().host[..] + }).to_string(); let engine = build_config.exec_engine.as_ref().cloned().unwrap_or({ Arc::new(Box::new(ProcessEngine)) }); @@ -244,9 +246,9 @@ impl<'a, 'cfg> Context<'a, 'cfg> { /// otherwise it corresponds to the target platform. fn dylib(&self, kind: Kind) -> CargoResult<(&str, &str)> { let (triple, pair) = if kind == Kind::Host { - (self.config.rustc_host(), &self.host_dylib) + (&self.config.rustc_info().host, &self.host_dylib) } else { - (&self.target_triple[..], &self.target_dylib) + (&self.target_triple, &self.target_dylib) }; match *pair { None => return Err(human(format!("dylib outputs are not supported \ diff --git a/src/cargo/ops/cargo_rustc/custom_build.rs b/src/cargo/ops/cargo_rustc/custom_build.rs index b2c98a41b..0c939dd59 100644 --- a/src/cargo/ops/cargo_rustc/custom_build.rs +++ b/src/cargo/ops/cargo_rustc/custom_build.rs @@ -63,13 +63,13 @@ pub fn prepare(pkg: &Package, target: &Target, req: Platform, .env("CARGO_MANIFEST_DIR", pkg.root()) .env("NUM_JOBS", &cx.jobs().to_string()) .env("TARGET", &match kind { - Kind::Host => cx.config.rustc_host(), + Kind::Host => &cx.config.rustc_info().host[..], Kind::Target => cx.target_triple(), }) .env("DEBUG", &profile.debuginfo.to_string()) .env("OPT_LEVEL", &profile.opt_level.to_string()) .env("PROFILE", if cx.build_config.release {"release"} else {"debug"}) - .env("HOST", &cx.config.rustc_host()); + .env("HOST", &cx.config.rustc_info().host); // Be sure to pass along all enabled features for this package, this is the // last piece of statically known information that we have. diff --git a/src/cargo/ops/cargo_rustc/fingerprint.rs b/src/cargo/ops/cargo_rustc/fingerprint.rs index b72931d19..05336eebf 100644 --- a/src/cargo/ops/cargo_rustc/fingerprint.rs +++ b/src/cargo/ops/cargo_rustc/fingerprint.rs @@ -165,8 +165,8 @@ fn calculate<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, v.sort(); v }); - let extra = util::short_hash(&(cx.config.rustc_version(), target, &features, - profile)); + let extra = util::short_hash(&(&cx.config.rustc_info().verbose_version, + target, &features, profile)); debug!("extra {:?} {:?} {:?} = {}", target, profile, features, extra); // Next, recursively calculate the fingerprint for all of our dependencies. diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 486ce8d5c..aac936656 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -3,7 +3,7 @@ use std::env; use std::ffi::OsString; use std::fs; use std::io::prelude::*; -use std::path::{self, Path, PathBuf}; +use std::path::{self, PathBuf}; use std::sync::Arc; use core::{SourceMap, Package, PackageId, PackageSet, Target, Resolve}; @@ -52,29 +52,6 @@ pub struct TargetConfig { pub overrides: HashMap, } -/// Run `rustc` to figure out what its current version string is. -/// -/// The second element of the tuple returned is the target triple that rustc -/// is a host for. -pub fn rustc_version>(rustc: P) -> CargoResult<(String, String)> { - let output = try!(try!(util::process(rustc.as_ref())) - .arg("-vV") - .exec_with_output()); - let output = try!(String::from_utf8(output.stdout).map_err(|_| { - internal("rustc -v didn't return utf8 output") - })); - let triple = { - let triple = output.lines().filter(|l| { - l.starts_with("host: ") - }).map(|l| &l[6..]).next(); - let triple = try!(triple.chain_error(|| { - internal("rustc -v didn't have a line for `host:`") - })); - triple.to_string() - }; - Ok((output, triple)) -} - // Returns a mapping of the root package plus its immediate dependencies to // where the compiled libraries are all located. pub fn compile_targets<'a, 'cfg: 'a>(targets: &[(&'a Target, &'a Profile)], @@ -336,10 +313,14 @@ fn rustc(package: &Package, target: &Target, profile: &Profile, return rustcs.into_iter().map(|(mut rustc, kind)| { let name = package.name().to_string(); let is_path_source = package.package_id().source_id().is_path(); - let show_warnings = package.package_id() == cx.resolve.root() || - is_path_source; - if !show_warnings { - rustc.arg("-Awarnings"); + let allow_warnings = package.package_id() == cx.resolve.root() || + is_path_source; + if !allow_warnings { + if cx.config.rustc_info().cap_lints { + rustc.arg("--cap-lints").arg("allow"); + } else { + rustc.arg("-Awarnings"); + } } let has_custom_args = profile.rustc_args.is_some(); let exec_engine = cx.exec_engine.clone(); diff --git a/src/cargo/ops/mod.rs b/src/cargo/ops/mod.rs index 24106aa7a..545187a98 100644 --- a/src/cargo/ops/mod.rs +++ b/src/cargo/ops/mod.rs @@ -2,7 +2,7 @@ pub use self::cargo_clean::{clean, CleanOptions}; pub use self::cargo_compile::{compile, compile_pkg, CompileOptions}; pub use self::cargo_compile::{CompileFilter, CompileMode}; pub use self::cargo_read_manifest::{read_manifest,read_package,read_packages}; -pub use self::cargo_rustc::{compile_targets, Compilation, Layout, Kind, rustc_version}; +pub use self::cargo_rustc::{compile_targets, Compilation, Layout, Kind}; pub use self::cargo_rustc::{Context, LayoutProxy}; pub use self::cargo_rustc::Platform; pub use self::cargo_rustc::{BuildOutput, BuildConfig, TargetConfig}; diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index 90c971e83..a3ccb29eb 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -12,8 +12,7 @@ use std::path::{Path, PathBuf}; use rustc_serialize::{Encodable,Encoder}; use toml; use core::{MultiShell, Package}; -use ops; -use util::{CargoResult, ChainError, internal, human}; +use util::{CargoResult, ChainError, Rustc, internal, human}; use util::toml as cargo_toml; @@ -22,9 +21,7 @@ use self::ConfigValue as CV; pub struct Config { home_path: PathBuf, shell: RefCell, - rustc_version: String, - /// The current host and default target of rustc - rustc_host: String, + rustc_info: Rustc, values: RefCell>, values_loaded: Cell, cwd: PathBuf, @@ -45,8 +42,7 @@ impl Config { This probably means that $HOME was not set.") })), shell: RefCell::new(shell), - rustc_version: String::new(), - rustc_host: String::new(), + rustc_info: Rustc::blank(), cwd: cwd, values: RefCell::new(HashMap::new()), values_loaded: Cell::new(false), @@ -92,11 +88,7 @@ impl Config { pub fn rustdoc(&self) -> &Path { &self.rustdoc } - /// Return the output of `rustc -v verbose` - pub fn rustc_version(&self) -> &str { &self.rustc_version } - - /// Return the host platform and default target of rustc - pub fn rustc_host(&self) -> &str { &self.rustc_host } + pub fn rustc_info(&self) -> &Rustc { &self.rustc_info } pub fn values(&self) -> CargoResult>> { if !self.values_loaded.get() { @@ -219,9 +211,7 @@ impl Config { } fn scrape_rustc_version(&mut self) -> CargoResult<()> { - let (rustc_version, rustc_host) = try!(ops::rustc_version(&self.rustc)); - self.rustc_version = rustc_version; - self.rustc_host = rustc_host; + self.rustc_info = try!(Rustc::new(&self.rustc)); Ok(()) } diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index ed4d079f9..b47e8095d 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -1,20 +1,21 @@ pub use self::config::Config; -pub use self::process_builder::{process, ProcessBuilder}; +pub use self::dependency_queue::Dependency; +pub use self::dependency_queue::{DependencyQueue, Fresh, Dirty, Freshness}; pub use self::errors::{CargoResult, CargoError, ChainError, CliResult}; pub use self::errors::{CliError, ProcessError}; -pub use self::errors::{process_error, internal_error, internal, human}; pub use self::errors::{Human, caused_human}; +pub use self::errors::{process_error, internal_error, internal, human}; +pub use self::graph::Graph; +pub use self::hex::{to_hex, short_hash}; +pub use self::lev_distance::{lev_distance}; pub use self::paths::{join_paths, path2bytes, bytes2path, dylib_path}; pub use self::paths::{normalize_path, dylib_path_envvar, without_prefix}; -pub use self::lev_distance::{lev_distance}; -pub use self::hex::{to_hex, short_hash}; -pub use self::dependency_queue::{DependencyQueue, Fresh, Dirty, Freshness}; -pub use self::dependency_queue::Dependency; -pub use self::graph::Graph; -pub use self::to_url::ToUrl; +pub use self::process_builder::{process, ProcessBuilder}; +pub use self::rustc::Rustc; +pub use self::sha256::Sha256; pub use self::to_semver::ToSemver; +pub use self::to_url::ToUrl; pub use self::vcs::{GitRepo, HgRepo}; -pub use self::sha256::Sha256; pub mod config; pub mod errors; @@ -32,3 +33,4 @@ mod dependency_queue; mod sha256; mod shell_escape; mod vcs; +mod rustc; diff --git a/src/cargo/util/rustc.rs b/src/cargo/util/rustc.rs new file mode 100644 index 000000000..0a3fbf69b --- /dev/null +++ b/src/cargo/util/rustc.rs @@ -0,0 +1,50 @@ +use std::path::Path; + +use util::{self, CargoResult, internal, ChainError}; + +pub struct Rustc { + pub verbose_version: String, + pub host: String, + pub cap_lints: bool, +} + +impl Rustc { + /// Run the compiler at `path` to learn varioues pieces of information about + /// it. + /// + /// If successful this function returns a description of the compiler along + /// with a list of its capabilities. + pub fn new>(path: P) -> CargoResult { + let mut cmd = try!(util::process(path.as_ref())); + cmd.arg("-vV"); + + let mut ret = Rustc::blank(); + let mut first = cmd.clone(); + first.arg("--cap-lints").arg("allow"); + let output = match first.exec_with_output() { + Ok(output) => { ret.cap_lints = true; output } + Err(..) => try!(cmd.exec_with_output()), + }; + ret.verbose_version = try!(String::from_utf8(output.stdout).map_err(|_| { + internal("rustc -v didn't return utf8 output") + })); + ret.host = { + let triple = ret.verbose_version.lines().filter(|l| { + l.starts_with("host: ") + }).map(|l| &l[6..]).next(); + let triple = try!(triple.chain_error(|| { + internal("rustc -v didn't have a line for `host:`") + })); + triple.to_string() + }; + Ok(ret) + } + + pub fn blank() -> Rustc { + Rustc { + verbose_version: String::new(), + host: String::new(), + cap_lints: false, + } + } +} diff --git a/tests/test_cargo_compile_git_deps.rs b/tests/test_cargo_compile_git_deps.rs index 91917a390..2f73a2f4e 100644 --- a/tests/test_cargo_compile_git_deps.rs +++ b/tests/test_cargo_compile_git_deps.rs @@ -1654,3 +1654,73 @@ test!(doctest_same_name { assert_that(p.cargo_process("test").arg("-v"), execs().with_status(0)); }); + +test!(lints_are_suppressed { + let a = git::new("a", |p| { + p.file("Cargo.toml", r#" + [project] + name = "a" + version = "0.5.0" + authors = [] + "#) + .file("src/lib.rs", " + use std::option; + ") + }).unwrap(); + + let p = project("foo") + .file("Cargo.toml", &format!(r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies] + a = {{ git = '{}' }} + "#, a.url())) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("build"), + execs().with_status(0).with_stdout(&format!("\ +{updating} git repository `[..]` +{compiling} a v0.5.0 ([..]) +{compiling} foo v0.0.1 ([..]) +", compiling = COMPILING, updating = UPDATING))); +}); + +test!(denied_lints_are_allowed { + let enabled = super::RUSTC.with(|r| r.cap_lints); + if !enabled { return } + + let a = git::new("a", |p| { + p.file("Cargo.toml", r#" + [project] + name = "a" + version = "0.5.0" + authors = [] + "#) + .file("src/lib.rs", " + #![deny(warnings)] + use std::option; + ") + }).unwrap(); + + let p = project("foo") + .file("Cargo.toml", &format!(r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies] + a = {{ git = '{}' }} + "#, a.url())) + .file("src/lib.rs", ""); + + assert_that(p.cargo_process("build"), + execs().with_status(0).with_stdout(&format!("\ +{updating} git repository `[..]` +{compiling} a v0.5.0 ([..]) +{compiling} foo v0.0.1 ([..]) +", compiling = COMPILING, updating = UPDATING))); +}); diff --git a/tests/tests.rs b/tests/tests.rs index b82c2ecf5..43d1c2fd9 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -16,6 +16,8 @@ extern crate url; #[macro_use] extern crate log; +use cargo::util::Rustc; + mod support; macro_rules! test { ($name:ident $expr:expr) => ( @@ -57,16 +59,19 @@ mod test_cargo_test; mod test_cargo_version; mod test_shell; +thread_local!(static RUSTC: Rustc = Rustc::new("rustc").unwrap()); + fn rustc_host() -> String { - cargo::ops::rustc_version("rustc").unwrap().1 + RUSTC.with(|r| r.host.clone()) } fn is_nightly() -> bool { - let version_info = cargo::ops::rustc_version("rustc").unwrap().0; - version_info.contains("-nightly") || version_info.contains("-dev") + RUSTC.with(|r| { + r.verbose_version.contains("-nightly") || + r.verbose_version.contains("-dev") + }) } fn can_panic() -> bool { - let host = cargo::ops::rustc_version("rustc").unwrap().1; - !host.contains("msvc") + RUSTC.with(|r| !r.host.contains("msvc")) } -- 2.30.2